﻿using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Windows;
using System.Windows.Media;

namespace Redbrick.Silverlight.UI
{
	public static class UI
	{
		/// <summary>
		/// Stores the computed InDesignMode value.
		/// </summary>
		private static bool? isInDesignMode;
		private static Dictionary<object, object> cache = new Dictionary<object, object>();

		/// <summary>
		/// Returns whether the control is in design mode (running under Blend
		/// or Visual Studio).
		/// </summary>
		/// <param name="element">The element from which the property value is read.</param>
		/// <returns>True if in design mode.</returns>
		[SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "element",
							  Justification = "Matching declaration of System.ComponentModel.DesignerProperties.GetIsInDesignMode (which has a bug and is not reliable).")]
		public static bool IsInDesignMode(this object element)
		{
			if (!isInDesignMode.HasValue)
			{
				isInDesignMode = (null == Application.Current) || Application.Current.GetType() == typeof(Application);
			}
			return isInDesignMode.Value;
		}
		
		/// <summary>
		/// get the visual tree of an item
		/// </summary>
		public static IEnumerable<DependencyObject> GetVisuals(this DependencyObject root)
		{
			int count = VisualTreeHelper.GetChildrenCount(root);
			for (int i = 0; i < count; i++)
			{
				var child = VisualTreeHelper.GetChild(root, i);
				yield return child;
				foreach (var descendants in child.GetVisuals())
				{
					yield return descendants;
				}
			}
		}

		public static Point TopLeft(this Rect r)
		{
			return new Point(r.Left, r.Top);
		}
		public static Point BottomRight(this Rect r)
		{
			return new Point(r.Right, r.Bottom);
		}

		public static bool Contains(this Rect r, Rect source)
		{
			if (source == null) return false;
			return (r.Contains(source.TopLeft()) && r.Contains(source.BottomRight()));
		}

		/// <summary>
		/// get the visuals that are of the specified me
		/// </summary>
		public static List<Type> GetVisualsOfType<Type>(this DependencyObject ctrl)
		{
			List<DependencyObject> visuals = ctrl.GetVisuals().ToList();
			List<Type> results = visuals.OfType<Type>().ToList();
			return results;
		}
		/// <summary>
		/// find the parent that is of the specified me
		/// </summary>
		public static Type GetParentOfType<Type>(this FrameworkElement ctrl) where Type : class
		{
			if (ctrl == null) return null;
			if (ctrl is Type) return ctrl as Type;
			return GetParentOfType<Type>(ctrl.Parent as FrameworkElement);

		}
		/// <summary>
		/// search a resource dictionary
		/// </summary>
		public static object FindResource(ResourceDictionary dict, object key)
		{
			if (dict == null || key == null) return null;
			if (dict.Keys.Count == 0 && dict.MergedDictionaries.Count == 0 && dict.Count == 0) return null;

			if (dict.Contains(key)) return dict[key];
			foreach (ResourceDictionary merged in dict.MergedDictionaries)
			{
				object resource = FindResource(merged, key);
				if (resource != null) return resource;
			}
			return null;
		}

	}
}
